﻿using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ChecksumGUI
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private FileInfo fiInputFile;
        private HashAlgorithm haMyHash;
        private BindedHash _currentBinding = BindedHash.None;

        private BindedHash CurrentBinding
        {
            get { return _currentBinding; }
            set
            {
                if (value != _currentBinding)
                {
                    _currentBinding = value;
                    UpdateBinding();
                }
            }
        }

        public MainWindow()
        {
            InitializeComponent();

            #region Declare Event Handlers
            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
            this.Drop += new DragEventHandler(MainWindow_Drop);
            cbxAlgorithm.SelectionChanged += new SelectionChangedEventHandler(cbxAlgorithm_SelectionChanged);
            btnBrowseFile.Click += new RoutedEventHandler(btnBrowseFile_Click);
            tbxInputString.TextChanged += new TextChangedEventHandler(tbxInputString_TextChanged);
            btnComputeStringHash.Click += new RoutedEventHandler(btnComputeStringHash_Click);
            btnComputeFileHash.Click += new RoutedEventHandler(btnComputeFileHash_Click);
            tbxComputedHash.TextChanged += new TextChangedEventHandler(tbxComputedHash_TextChanged);
            tbxComputedHash.GotFocus += new RoutedEventHandler(TextBox_SelectAll);
            tbxComputedHash.GotMouseCapture += new MouseEventHandler(TextBox_SelectAll);
            tbxCompareHash.TextChanged += new TextChangedEventHandler(tbxCompareHash_TextChanged);
            tbxCompareHash.GotFocus += new RoutedEventHandler(TextBox_SelectAll);
            tbxCompareHash.GotMouseCapture += new MouseEventHandler(TextBox_SelectAll);
            btnCopyHash.Click += new RoutedEventHandler(btnCopyHash_Click);
            #endregion
        }

        #region Event Handlers
        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            //Init UI
            cbxAlgorithm.SelectedIndex = 0;

        }

        void MainWindow_Drop(object sender, DragEventArgs e)
        {
            if (e.Data is DataObject && ((DataObject)e.Data).ContainsFileDropList())
            {
                System.Collections.Specialized.StringCollection dropedFiles = ((DataObject)e.Data).GetFileDropList();

                if (dropedFiles.Count == 1)
                {
                    fiInputFile = new FileInfo(dropedFiles[0]);
                    tbxInputFile.Text = fiInputFile.FullName;
                    if (CurrentBinding == BindedHash.File) CurrentBinding = BindedHash.None;
                }
            }
        }

        void tbxInputString_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (CurrentBinding == BindedHash.String) CurrentBinding = BindedHash.None;
        }

        void cbxAlgorithm_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            switch ((String)((ComboBoxItem)e.AddedItems[0]).Content)
            {
                case "MD5":
                    haMyHash = MD5.Create();
                    break;
                case "SHA1":
                    haMyHash = SHA1.Create();
                    break;
                case "SHA256":
                    haMyHash = SHA256.Create();
                    break;
                case "SHA384":
                    haMyHash = SHA384.Create();
                    break;
                case "SHA512":
                    haMyHash = SHA512.Create();
                    break;
                default :
                    haMyHash = null;
                    break;
            }
        }

        void btnBrowseFile_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog ofdInputFile = new OpenFileDialog();
            if (ofdInputFile.ShowDialog() == true)
            {
                fiInputFile = new FileInfo(ofdInputFile.FileName);
                tbxInputFile.Text = fiInputFile.FullName;
                if (CurrentBinding == BindedHash.File) CurrentBinding = BindedHash.None;
            }
        }

        void btnComputeFileHash_Click(object sender, RoutedEventArgs e)
        {
            if (fiInputFile == null)
            {
                MessageBox.Show("Select input file first.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            else if (!fiInputFile.Exists)
            {
                MessageBox.Show("Missing input file", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            else
            {
                tbxComputedHash.Text = HashToString(ComputeFileHash(fiInputFile));
                this.CurrentBinding = BindedHash.File;
            }
        }

        void btnComputeStringHash_Click(object sender, RoutedEventArgs e)
        {
            String InputString = tbxInputString.Text;

            if (InputString.StartsWith(" ") || InputString.EndsWith(" "))
            {
                MessageBoxResult TrimResult = MessageBox.Show("Inputted text starts or ends with whitespace.\r\nDo you want to trim whitespaces ?", "Warning", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);

                if (TrimResult == MessageBoxResult.Cancel)
                {
                    // Cancel
                    return;
                }
                else if (TrimResult == MessageBoxResult.Yes)
                {
                    InputString = InputString.Trim();
                    tbxInputString.Text = InputString;
                }
            }

            tbxComputedHash.Text = HashToString(ComputeStringHash(InputString));
            this.CurrentBinding = BindedHash.String;
        }

        void tbxComputedHash_TextChanged(object sender, TextChangedEventArgs e)
        {
            btnCopyHash.IsEnabled = (tbxComputedHash.Text != "");
            UpdateCompare();
        }

        void tbxCompareHash_TextChanged(object sender, TextChangedEventArgs e)
        {
            UpdateCompare();
        }

        void btnCopyHash_Click(object sender, RoutedEventArgs e)
        {
            if (tbxComputedHash.Text != "")
            {
                Clipboard.SetText(tbxComputedHash.Text, TextDataFormat.Text);
            }
        }

        void TextBox_SelectAll(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            ((TextBox)sender).SelectAll();
        }

        #endregion

        #region Private Functions
        private Byte[] ComputeStringHash(String InputString)
        {
            Byte[] inputBytes = Encoding.ASCII.GetBytes(InputString);
            return haMyHash.ComputeHash(inputBytes);
        }

        private Byte[] ComputeFileHash(FileInfo InputFile)
        {
            Byte[] result;

            using (FileStream fsInputFile = InputFile.OpenRead())
            {
                result = haMyHash.ComputeHash(fsInputFile);

                fsInputFile.Close();
            }

            return result;
        }

        private String HashToString(Byte[] ComputedHash)
        {
            StringBuilder sbHashString = new StringBuilder();

            for (int i = 0; i < ComputedHash.Length; i++)
            {
                sbHashString.Append(ComputedHash[i].ToString("x2"));
            }

            return sbHashString.ToString();
        }

        private void UpdateCompare()
        {
            String ComputedHash = tbxComputedHash.Text;
            String CompareHash = tbxCompareHash.Text.Trim();

            if (ComputedHash != "" && CompareHash != "")
            {
                if (String.Compare(ComputedHash, CompareHash, true) == 0)
                {
                    imgCompareError.Visibility = System.Windows.Visibility.Hidden;
                    imgCompareOK.Visibility = System.Windows.Visibility.Visible;
                }
                else
                {
                    imgCompareError.Visibility = System.Windows.Visibility.Visible;
                    imgCompareOK.Visibility = System.Windows.Visibility.Hidden;
                }
            }
            else
            {
                imgCompareError.Visibility = System.Windows.Visibility.Hidden;
                imgCompareOK.Visibility = System.Windows.Visibility.Hidden;
            }
        }

        private void UpdateBinding()
        {
            tbxComputedHash.Background = (CurrentBinding == BindedHash.None ? Brushes.White : (SolidColorBrush)Resources["ValidBrush"]);
            tbxInputString.Background = (CurrentBinding == BindedHash.String ? (SolidColorBrush)Resources["ValidBrush"] : Brushes.White);
            tbxInputFile.Background = (CurrentBinding == BindedHash.File ? (SolidColorBrush)Resources["ValidBrush"] : Brushes.White);
        }
        
        #endregion

    }

    enum BindedHash
    {
        String,
        File,
        None
    }
}
